package com.example.myapplication;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.Nullable;

/**
 * Created by Rays on 2019/11/23.
 */
public class WeekTimeView extends View {

    private Paint timePaint, weekPaint, itemNormalPaint, itemCheckedPaint, checkedIconPaint;
    private float columnWidth, rowHeight, itemWidth, itemHeight, radius, centerX, centerY, weekHeight, weekY, timeWidth, timeY;
    private Path checkIconPath = new Path();

    private String[] weekTexts = new String[]{"日", "一", "二", "三", "四", "五", "六"};
    private final Item[][] items = new Item[24][7];

    private OnCheckedChangeListener onCheckedChangeListener;

    public WeekTimeView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);

        DisplayMetrics metrics = getResources().getDisplayMetrics();

        timePaint = new Paint();
        timePaint.setColor(Color.parseColor("#333333"));
        timePaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 12, metrics));

        weekPaint = new Paint(timePaint);
        weekPaint.setTextAlign(Paint.Align.CENTER);

        itemNormalPaint = new Paint();
        itemNormalPaint.setColor(Color.parseColor("#F8F6F7"));
        itemNormalPaint.setAntiAlias(true);
        itemNormalPaint.setStyle(Paint.Style.FILL);

        itemCheckedPaint = new Paint(itemNormalPaint);
        itemCheckedPaint.setColor(Color.parseColor("#FFD3D3"));

        checkedIconPaint = new Paint(itemNormalPaint);
        checkedIconPaint.setColor(Color.parseColor("#FF5C5C"));
        checkedIconPaint.setStyle(Paint.Style.STROKE);
        checkedIconPaint.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, metrics));

        itemHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, metrics);
        columnWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, metrics);
        rowHeight = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4, metrics);
        radius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, metrics);

        float padding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, metrics);

        Paint.FontMetrics fontMetrics = weekPaint.getFontMetrics();
        weekHeight = fontMetrics.bottom - fontMetrics.top + padding;
        timeWidth = timePaint.measureText("00:00") + padding;

        initItems();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMS = MeasureSpec.getSize(widthMeasureSpec);
        int width = widthMS - getPaddingLeft() - getPaddingRight();
        Log.i("WeekTimeView", "onMeasure widthMS: " + widthMS + " width: " + width);
        itemWidth = (width - timeWidth - columnWidth * 6) / 7;
        itemHeight = Math.min(itemWidth, itemHeight);
        centerX = itemWidth / 2;
        centerY = itemHeight / 2;
        Paint.FontMetrics fontMetrics = weekPaint.getFontMetrics();
        weekY = -fontMetrics.ascent;
        timeY = itemHeight / 2 - (fontMetrics.ascent + fontMetrics.descent) / 2;

        initCheckIconPath();
        initItemsXY();

        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.UNSPECIFIED) {
            heightMeasureSpec = (int) (weekHeight + itemHeight * 24 + rowHeight * 23 + getPaddingTop() + getPaddingBottom() + 0.5f);
            setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
        } else {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    }

    private void initCheckIconPath() {
        float iconWidth = itemHeight / 3;
        // 短线 iconWidth / 3
        // 长线 iconWidth / 3 * 2
        float startX = itemWidth / 2 - iconWidth / 2;
        float offset = iconWidth / 3;
        checkIconPath.moveTo(startX, centerY);
        checkIconPath.lineTo(startX + offset, centerY + offset);
        checkIconPath.lineTo(startX + iconWidth, centerY - offset);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Log.i("WeekTimeView", "onDraw width: " + getWidth());
        canvas.drawColor(Color.WHITE);

        canvas.translate(getPaddingLeft(), getPaddingTop());
        canvas.save();

        canvas.drawText(" DAY", 0, weekY, timePaint);
        canvas.translate(timeWidth, 0);

        for (String weekText : weekTexts) {
            canvas.drawText(weekText, centerX, weekY, weekPaint);
            canvas.translate(itemWidth + columnWidth, 0);
        }
        canvas.restore();
        canvas.translate(0, weekHeight);
        canvas.save();


        for (int i = 0; i < 24; i++) {
            canvas.drawText(items[i][0].time, 0, timeY, timePaint);
            canvas.translate(timeWidth, 0);
            for (int j = 0; j < 7; j++) {
                if (items[i][j].isChecked) {
                    canvas.drawRoundRect(0, 0, itemWidth, itemHeight, radius, radius, itemCheckedPaint);
                    canvas.drawPath(checkIconPath, checkedIconPaint);
                } else {
                    canvas.drawRoundRect(0, 0, itemWidth, itemHeight, radius, radius, itemNormalPaint);
                }
                canvas.translate(itemWidth + columnWidth, 0);
            }

            canvas.restore();
            canvas.translate(0, itemHeight + rowHeight);
            canvas.save();
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (getAvailableItem(event.getX(), event.getY()) != null) {
                    return true;
                }
                break;
            case MotionEvent.ACTION_UP:
                Item item = getAvailableItem(event.getX(), event.getY());
                if (item != null) {
                    item.isChecked = !item.isChecked;
                    invalidate();
                    if (onCheckedChangeListener != null) {
                        onCheckedChangeListener.onCheckedChanged(item);
                    }
                    return true;
                }
                break;
        }
        return false;
    }

    private Item getAvailableItem(float x, float y) {
        int dx = (int) (x - getPaddingLeft() - timeWidth);
        int dy = (int) (y - getPaddingTop() - weekHeight);
        if (dx < 0 || dy < 0) {
            return null;
        }
        int itemW = (int) (itemWidth + columnWidth);
        int itemH = (int) (itemHeight + rowHeight);

        int column = dx / itemW;
        int row = dy / itemH;

        if (column < 7 && row < 24 && dx < column * itemW + itemWidth && dy < row * itemW + itemHeight) {
            return items[row][column];
        }
        return null;
    }

    private void initItems() {
        for (int i = 0; i < 24; i++) {
            for (int j = 0; j < 7; j++) {
                Item item = new Item();
                item.time = (i < 10 ? "0" + i : String.valueOf(i)) + ":30";
                item.week = j;
                items[i][j] = item;
            }
        }
    }

    private void initItemsXY() {
        float x = getPaddingLeft() + timeWidth;
        float y = getPaddingTop() + weekHeight;
        for (int i = 0; i < 24; i++) {
            for (int j = 0; j < 7; j++) {
                items[i][j].x = x;
                items[i][j].y = y;
                x = x + itemWidth + columnWidth;
            }
            y = y + itemHeight + rowHeight;
        }
    }

    public void setOnCheckedChangeListener(OnCheckedChangeListener onCheckedChangeListener) {
        this.onCheckedChangeListener = onCheckedChangeListener;
    }

    public static final class Item {
        float x;
        float y;
        String time;
        int week;
        boolean isChecked;
    }

    public interface OnCheckedChangeListener {

        void onCheckedChanged(Item item);

    }

}
